import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
import { ElMessage } from 'element-plus';
import { Local, Session } from '/@/utils/storage';
import { clog } from '/@/utils';

// 业务使用此文件调用接口, 框架使用axios-utils.ts, wcf使用requestWCF.ts
// 配置新建一个 axios 实例
export const service = axios.create({
	baseURL: window.__env__.VITE_API_URL as any,
	timeout: 30000,
	headers: { 'Content-Type': 'application/json' },
});

// token 键定义
export const accessTokenKey = 'access-token';
export const refreshAccessTokenKey = `x-${accessTokenKey}`;

// 获取 token
export const getToken = () => {
	return Local.get(accessTokenKey);
};

// 清除 token
export const clearAccessTokens = () => {
	Local.remove(accessTokenKey);
	Local.remove(refreshAccessTokenKey);

	// 清除其他
	Session.clear();

	// 刷新浏览器
	// window.location.reload(); //yizhe 注释20241025 : 没登录前调用了没有权限的接口后会不断重复刷新
};

// axios 默认实例
export const axiosInstance: AxiosInstance = axios;

// 添加请求拦截器
service.interceptors.request.use(
	(config) => {
		// // 在发送请求之前做些什么 token
		// if (Session.get('token')) {
		// 	(<any>config.headers).common['Authorization'] = `${Session.get('token')}`;
		// }

		// 获取本地的 token
		const accessToken = Local.get(accessTokenKey);
		if (accessToken && typeof accessToken === 'string') {
			// 将 token 添加到请求报文头中
			config.headers!['Authorization'] = `Bearer ${accessToken}`;

			// 判断 accessToken 是否过期
			const jwt: any = decryptJWT(accessToken);
			const exp = getJWTDate(jwt.exp as number);

			// token 已经过期
			if (new Date() >= exp) {
				// 获取刷新 token
				const refreshAccessToken = Local.get(refreshAccessTokenKey);

				// 携带刷新 token
				if (refreshAccessToken) {
					config.headers!['X-Authorization'] = `Bearer ${refreshAccessToken}`;
				}
			}
			// debugger
			// get请求映射params参数
			if (config.method?.toLowerCase() === 'get' && config.data) {
				let url = config.url + '?' + tansParams(config.data);
				url = url.slice(0, -1);
				config.data = {};
				config.url = url;
			}
		}
		return config;
	},
	(error) => {
		// 对请求错误做些什么
		console.log(JSON.stringify(error));
		return Promise.reject(error);
	}
);

// 添加响应拦截器
service.interceptors.response.use(
	(res) => {
		// 收到的服务器的响应数据
		// 获取状态码和返回数据
		var status = res.status;
		// 处理 401
		if (status === 401) {
			clearAccessTokens();
		}

		// 处理未进行规范化处理的
		if (status >= 400) {
			throw new Error(res.statusText || 'Request Error.');
		}

		// 读取响应报文头 token 信息
		var accessToken = res.headers[accessTokenKey];
		var refreshAccessToken = res.headers[refreshAccessTokenKey];

		// 判断是否是无效 token
		if (accessToken === 'invalid_token') {
			clearAccessTokens();
		}
		// 判断是否存在刷新 token，如果存在则存储在本地
		else if (refreshAccessToken && accessToken && accessToken !== 'invalid_token') {
			Local.set(accessTokenKey, accessToken);
			Local.set(refreshAccessTokenKey, refreshAccessToken);
		}

		let data = res.data;
		/** res.data的格式
		{
			"code": 500,  // 成功时这里是200
			"type": "error",
			"message": "“`”附近有语法错误。\r\n“`”附近有语法错误。",
			"result": '成功时这里放数据',
			"extras": null,
			"time": "2025-02-24 15:14:26"
		} */

		// 处理规范化结果错误
		if (data && data.hasOwnProperty('errors') && data.errors) {
			throw new Error(JSON.stringify(data.errors || 'Request Error.'));
		}

		// 响应拦截及自定义处理
		if (data.code === 401) {
			clearAccessTokens();
		} else if (data.code === undefined) {
			return Promise.resolve(res);
		} else if (data.code !== 200) {
			clog('服务端错误', res);
			var title = '';
			// 判断 data.message 是否为对象
			if (data.message && typeof data.message == 'object') {
				title = JSON.stringify(data.message);
			} else {
				title = data.message;
			}
			var msg = '<div style="text-align:center; color: #000"><h2>' + title + '</h2> </div> <br> 错误代码: 500 <br> 请求地址: ' + res.config?.baseURL + res.config?.url;
			ElMessage({
				dangerouslyUseHTMLString: true,
				message: msg,
				type: 'error',
				showClose: true,
				duration: 6000,
				grouping: true,
			});
			return Promise.reject(); // 抛出异常,中断返回，由main.ts中的errorHandler捕获
			// throw new Error(message);
		} else {
			// return res;
			return data.result; // 只输出最终的数据，只适合Admin.Net框架
		}
	},
	(error) => {
		// 处理响应错误，没有收到服务器响应的情况
		if (error.response) {
			if (error.response.status === 401) {
				clearAccessTokens();
			}
		}
		console.log(JSON.stringify(error));
		let url = error.config?.baseURL + error.config?.url;
		let msg = '';
		// 对响应错误做点什么
		if (error.message.indexOf('timeout') != -1) {
			msg = '请求超时';
		} else if (error.message == 'Network Error') {
			msg = '网络错误';
		} else if (error.response?.status == 404) {
			msg = '资源不存在，错误的地址或入参';
		} else {
			if (error.response?.data) msg = '错误: ' + error.response?.statusText;
			else msg = '接口路径找不到';
		}

		ElMessage({
			dangerouslyUseHTMLString: true,
			message: `<div style="text-align:center; color: #000"><h2> ${msg} </h2> </div>错误代码 ${error.response ? error.response.status : '400'}  <br> 请求地址: ${url}`,
			type: 'error',
			showClose: true,
			duration: 6000,
			grouping: true,
		});
		return Promise.reject(); // 中断await代码,抛出空异常，不需要main.js拦截显示
	}
);

/**
 *  参数处理
 * @param {*} params  参数
 */
export function tansParams(params: any) {
	let result = '';
	for (const propName of Object.keys(params)) {
		const value = params[propName];
		var part = encodeURIComponent(propName) + '=';
		if (value !== null && value !== '' && typeof value !== 'undefined') {
			if (typeof value === 'object') {
				for (const key of Object.keys(value)) {
					if (value[key] !== null && value[key] !== '' && typeof value[key] !== 'undefined') {
						let params = propName + '[' + key + ']';
						var subPart = encodeURIComponent(params) + '=';
						result += subPart + encodeURIComponent(value[key]) + '&';
					}
				}
			} else {
				result += part + encodeURIComponent(value) + '&';
			}
		}
	}
	return result;
}

/**
 * 解密 JWT token 的信息
 * @param token jwt token 字符串
 * @returns <any>object
 */
export function decryptJWT(token: string): any {
	token = token.replace(/_/g, '/').replace(/-/g, '+');
	var json = decodeURIComponent(escape(window.atob(token.split('.')[1])));
	return JSON.parse(json);
}

/**
 * 将 JWT 时间戳转换成 Date
 * @description 主要针对 `exp`，`iat`，`nbf`
 * @param timestamp 时间戳
 * @returns Date 对象
 */
export function getJWTDate(timestamp: number): Date {
	return new Date(timestamp * 1000);
}

/**
 * Ajax请求，如果成功返回result字段，如果不成功提示错误信息
 * @description Ajax请求
 * @config AxiosRequestConfig 请求参数
 * @returns 返回对象
 */
export function request2(config: AxiosRequestConfig<any>): any {
	return new Promise((resolve, reject) => {
		service(config)
			.then((res) => {
				if (res.data.type == 'success') {
					resolve(res.data.result);
				} else {
					console.log('res', res);
					ElMessage.success(res.data.message);
				}
			})
			.catch((res) => {
				console.log('res', res);
				ElMessage({
					message: '<div style="text-align:center;"><h2>调用接口异常</h2> </div> <br> 错误代码: request2 <br> 错误消息: ' + res,
					type: 'error',
					showClose: true,
					duration: 0,
					grouping: true,
				});

				reject(res);
			});
	});
}
// 导出 axios 实例
export default service;
